#include "sockopt.h"
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netfilter.h>

#define BUFFER_LEN_MAX 1024
static char buffer[BUFFER_LEN_MAX];

/* setsockopt 回调处理函数 */
int setsockopt_handler(struct sock *sk, int optval, void __user *user, unsigned int len)
{
	switch (optval) {
	case SOCKOPT_SET_BUFFER:
		if (copy_from_user((void *)&buffer, user, len) != 0) {
			return -EFAULT;
		}

		break;
	default:
		printk(KERN_INFO "invalid setsockopt opt : %d\n", optval);
		return -EFAULT;
	}

	printk(KERN_INFO "buffer[]: %s\n", buffer);
	return 0;
}

/* getsockopt 回调处理函数 */
int getsockopt_handler(struct sock *sk, int optval, void __user *user, int *len)
{
	unsigned int cpy_len;

	cpy_len = *len > BUFFER_LEN_MAX ? BUFFER_LEN_MAX : *len;
	switch (optval) {
	case SOCKOPT_GET_BUFFER:
		if (copy_to_user(user, (void *)&buffer[0], cpy_len) != 0) {
			printk(KERN_INFO "getsockopt_handler fail \n");
			return -EFAULT;
		}

		break;
	default:
		printk(KERN_INFO "unrecognized getsockopt optvalue : %d\n", optval);
		return -EFAULT;
	}

	return 0;
}

/* 定义nf_sockopt_ops结构体 */
static struct nf_sockopt_ops sockopt_ops_test = {
	.pf 			= PF_INET,
	.set_optmin 	= SOCKOPT_SET_MIN,
	.set_optmax 	= SOCKOPT_SET_MAX,
	.set 			= setsockopt_handler,
	.get_optmin 	= SOCKOPT_GET_MIN,
	.get_optmax 	= SOCKOPT_GET_MAX,
	.get 			= getsockopt_handler,
};

static __init int sockopt_test_init(void)
{
	int result;
	/* 注册sockopt */
	result = nf_register_sockopt(&sockopt_ops_test);
	if (result != 0) {
		printk("register sockopt error!\n");
	}

	printk("sockopt_test register success !\n");
	return 0;
}

static __exit void sockopt_test_exit(void)
{
	/* 注销sockopt */
	nf_unregister_sockopt(&sockopt_ops_test);
	printk("sockopt_test unregister\n");
}

module_init(sockopt_test_init);
module_exit(sockopt_test_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Stone");

